home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
DJSRC111.ZIP
/
go32
/
ed
/
symsaout.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-28
|
16KB
|
706 lines
/* This is file SYMS.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dos.h>
#include <io.h>
#include "ed.h"
#define DO_SYMS 0
int undefined_symbol=0;
#define Ofs(n) ((int)&(((TSS *)0)->n))
struct {
char *name;
int size;
int ofs;
} regs[] = {
"%eip", 4, Ofs(tss_eip),
"%eflags", 4, Ofs(tss_eflags),
"%eax", 4, Ofs(tss_eax),
"%ebx", 4, Ofs(tss_ebx),
"%ecx", 4, Ofs(tss_ecx),
"%edx", 4, Ofs(tss_edx),
"%esp", 4, Ofs(tss_esp),
"%ebp", 4, Ofs(tss_ebp),
"%esi", 4, Ofs(tss_esi),
"%edi", 4, Ofs(tss_edi),
"%ax", 2, Ofs(tss_eax),
"%bx", 2, Ofs(tss_ebx),
"%cx", 2, Ofs(tss_ecx),
"%dx", 2, Ofs(tss_edx),
"%ah", 1, Ofs(tss_eax)+1,
"%bh", 1, Ofs(tss_ebx)+1,
"%ch", 1, Ofs(tss_ecx)+1,
"%dh", 1, Ofs(tss_edx)+1,
"%al", 1, Ofs(tss_eax),
"%bl", 1, Ofs(tss_ebx),
"%cl", 1, Ofs(tss_ecx),
"%dl", 1, Ofs(tss_edx),
0, 0, 0
};
#if !DO_SYMS
void syms_init(char *fname) {}
void syms_list(int byval) {}
void syms_listwild(char *pattern) {}
word32 syms_name2val(char *name)
{
if (isdigit(name[0]))
{
int v;
if (strncmp(name, "0x", 2) == 0)
sscanf(name+2, "%x", &v);
else
sscanf(name, "%d", &v);
undefined_symbol = 0;
return v;
}
else
{
undefined_symbol = 1;
return 0;
}
}
char *syms_val2name(word32 val, word32 *delta)
{
static char noname_buf[20];
sprintf(noname_buf, "%#lx", val);
*delta = 0;
return noname_buf;
}
char *syms_val2line(word32 val, int *lineret, int exact)
{
return 0;
}
#else
#define SYMADDR 0xa0000000
#define SYMSPACE ((sizeof(TSS) + 1023) & ~1023) /* collect this many symbols in real mode */
static word32 sym_brk=SYMADDR;
static word32 sym_page=SYMADDR;
static char *sym_ptr;
static char *sym_buffer;
static int sym_left;
word32 salloc(word32 size)
{
word32 r = sym_brk;
size = (size + 3) & ~3;
sym_brk += size;
return r;
}
void symwrite(void *ptr,int size)
{
size = (size + 3) & ~3;
if(size <= 0) return;
while(sym_left < size) {
if(sym_left != 0) {
memcpy(sym_ptr,ptr,sym_left);
size -= sym_left;
ptr = (void *)((char *)ptr + sym_left);
}
memput(sym_page,sym_buffer,SYMSPACE);
sym_page += SYMSPACE;
sym_left = SYMSPACE;
sym_ptr = sym_buffer;
}
if(size > 0) {
memcpy(sym_ptr,ptr,size);
sym_ptr += size;
sym_left -= size;
}
}
void symwrite_at(word32 addr,void *ptr,int size)
{
size = (size + 3) & ~3;
if(size <= 0) return;
if(addr < sym_page) {
word32 written_size = sym_page - addr;
if(written_size < size) {
memput(addr,ptr,(word16)written_size);
addr += written_size;
size -= (int)written_size;
ptr = (void *)((char *)ptr + (int)written_size);
}
else {
memput(addr,ptr,size);
size = 0;
}
}
if(size > 0) {
int offset = (int)(addr - sym_page);
memcpy(&sym_buffer[offset],ptr,size);
}
}
#define symsput(where,ptr,size) memput(where,ptr,size)
#define symsget(where,ptr,size) memget(where,ptr,size)
typedef struct SYMTREE {
word32 me;
word32 nleft, nright, ndown;
word32 vleft, vright, vdown;
word32 val;
word32 type;
word32 name_len;
} SYMTREE;
typedef struct FILENODE {
word32 me;
word32 next;
word32 line_list;
word32 first_addr, last_addr;
word32 name_len;
} FILENODE;
typedef struct LINENODE {
word32 me;
word32 next;
word32 num;
word32 addr;
} LINENODE;
static word32 symtree_root=0;
static word32 file_list=0;
static char tmps[256];
static char tmps2[256];
static symtree_print(word32 s, int byval, int level)
{
SYMTREE tmp;
if (s == 0)
return;
symsget(s, &tmp, sizeof(tmp));
if (byval)
symtree_print(tmp.vleft, byval, level+1);
else
symtree_print(tmp.nleft, byval, level+1);
symsget(tmp.me+sizeof(tmp), tmps, tmp.name_len);
printf("0x%08lx 0x%08lx %*s%s\n", tmp.val, tmp.type, level, "", tmps);
if (byval)
symtree_print(tmp.vdown, byval, level);
else
symtree_print(tmp.ndown, byval, level);
if (byval)
symtree_print(tmp.vright, byval, level+1);
else
symtree_print(tmp.nright, byval, level+1);
}
void syms_list(v)
{
symtree_print(symtree_root, v, 0);
}
typedef struct SYM_ENTRY {
word32 string_off;
word8 type;
word8 other;
word16 desc;
word32 val;
} SYM_ENTRY;
void syms_init(char *fname)
{
GNU_AOUT header;
int j, per, oldper=-1;
word32 nsyms, i;
FILE *fd,*sfd;
word32 sfd_base,sfd_pos;
SYM_ENTRY sym;
char *strings, *cp;
word32 string_size;
word32 last_dot_o=0;
FILENODE filen;
LINENODE linen;
SYMTREE temp;
char symbuf[SYMSPACE];
sym_ptr = sym_buffer = symbuf;
sym_left = SYMSPACE;
filen.me = 0;
linen.me = 0;
fd = fopen(fname, "rb");
sfd = fopen(fname, "rb");
fread(&header, sizeof(header), 1, fd);
switch((word16)header.info) {
case 0x014c:
fseek(fd, 0xa8L, 0);
fread(&header, sizeof(header), 1, fd);
fseek(fd, 0xa8+sizeof(header) + header.tsize + header.dsize, 0);
break;
case 0x010b:
case 0x0107:
fseek(fd, sizeof(header)+header.tsize+header.dsize+header.txrel+header.dtrel, 0);
break;
default:
fclose(fd);
fclose(sfd);
return;
}
printf("Reading symbols... 0%%");
fflush(stdout);
/* reserve space for the symbol tree root pointer */
salloc(sizeof(word32));
symwrite(&symtree_root,sizeof(word32));
nsyms = header.symsize / sizeof(SYM_ENTRY);
fseek(sfd, ftell(fd)+header.symsize, 0);
sfd_pos = sfd_base = ftell(sfd);
for (i=0; i<nsyms; i++)
{
if (nsyms > 1)
per = i*100L/(nsyms-1);
else
per = 100;
if (per != oldper)
{
printf("\b\b\b\b%3d%%", per);
fflush(stdout);
oldper = per;
}
fread(&sym, sizeof(sym),1, fd);
if (sym.string_off) {
word32 where = sfd_base + sym.string_off;
if(where != sfd_pos) fseek(sfd,(sfd_pos = where),0);
for(cp = tmps2; (*cp = getc(sfd)) != '\0'; cp++);
sfd_pos += (int)(cp - tmps2) + 1;
}
switch (sym.type)
{
case N_TEXT:
case N_TEXT | N_EXT:
cp = tmps2;
cp += strlen(cp) - 2;
if (strcmp(cp, ".o") == 0)
{
last_dot_o = sym.val;
if (filen.me && (filen.last_addr == 0))
{
filen.last_addr = last_dot_o - 1;
}
break;
}
if (strncmp(tmps2, "___gnu", 6) == 0)
break;
if (strcmp(cp, "d.") == 0) /* as in gcc_compiled. */
break;
case N_DATA:
case N_DATA | N_EXT:
case N_ABS:
case N_ABS | N_EXT:
case N_BSS:
case N_BSS | N_EXT:
case N_FN:
case N_SETV:
case N_SETV | N_EXT:
case N_SETA:
case N_SETA | N_EXT:
case N_SETT:
case N_SETT | N_EXT:
case N_SETD:
case N_SETD | N_EXT:
case N_SETB:
case N_SETB | N_EXT:
case N_INDR:
case N_INDR | N_EXT:
if (sym.string_off) {
memset(&temp, 0, sizeof(SYMTREE));
temp.name_len = strlen(tmps2) + 1;
temp.me = salloc(sizeof(temp)+temp.name_len);
temp.val = sym.val;
temp.type = sym.type;
temp.nleft = symtree_root;
symwrite(&temp, sizeof(temp));
symwrite(tmps2, temp.name_len);
symtree_root = temp.me;
}
break;
case N_SO:
if(filen.me != 0) {
/* update previous file name symbol */
symwrite_at(filen.me,&filen, sizeof(filen));
}
memset(&filen, 0, sizeof(FILENODE));
filen.name_len = strlen(tmps2)+1;
filen.me = salloc(sizeof(FILENODE)+filen.name_len);
filen.next = file_list;
file_list = filen.me;
filen.first_addr = last_dot_o;
symwrite(&filen, sizeof(filen));
symwrite(tmps2, filen.name_len);
break;
case N_SLINE:
memset(&linen, 0, sizeof(linen));
linen.me = salloc(sizeof(LINENODE));
linen.next = filen.line_list;
filen.line_list = linen.me;
linen.num = sym.desc;
linen.addr = sym.val;
symwrite(&linen, sizeof(linen));
break;
}
}
fclose(fd);
fclose(sfd);
printf(" %ld symbol%s read\n", nsyms, nsyms==1 ? "" : "s");
if(filen.me != 0) {
/* update the last file name symbol */
symwrite_at(filen.me,&filen, sizeof(filen));
}
if(sym_left < SYMSPACE) {
/* flush symbol read buffer if necessary */
memput(sym_page,sym_buffer,(SYMSPACE - sym_left));
}
if(symtree_root) {
/*
* Construct symbol tree from the simple linked list built above.
* Do it using a 32-bit protected mode code fragment generated
* from the code in "sym32.c" using GCC
*/
static char do_symsort32[] = {
# include "sym32.h"
0
};
TSS *old_tss = tss_ptr;
printf("Building symbol trees... ");
fflush(stdout);
tss_ptr = &a_tss;
memput(SYMADDR,&symtree_root,sizeof(word32)); /* pass root to 32-bit code */
memcpy(symbuf,&a_tss,sizeof(TSS)); /* save arena TSS */
a_tss.tss_eip = 0xe0000000L + /* set it up */
((word32)(word16)FP_SEG(do_symsort32) << 4) +
(word32)(word16)FP_OFF(do_symsort32);
a_tss.tss_esp -= 0x20;
go_til_done();
memcpy(&a_tss,symbuf,sizeof(TSS)); /* restore ARENA TSS */
tss_ptr = old_tss;
printf("DONE\n");
}
}
word32 syms_name2val(char *name)
{
SYMTREE s;
int cval, idx, sign=1, i;
word32 v;
char *cp;
undefined_symbol = 0;
idx = 0;
sscanf(name, "%s", name);
if (name[0] == 0)
return 0;
if (name[0] == '-')
{
sign = -1;
name++;
}
else if (name[0] == '+')
{
name++;
}
if (isdigit(name[0]))
{
if (sign == -1)
return -strtol(name, 0, 0);
return strtol(name, 0, 0);
}
cp = strpbrk(name, "+-");
if (cp)
idx = cp-name;
else
idx = strlen(name);
if (name[0] == '%') /* register */
{
for (i=0; regs[i].name; i++)
if (strncmp(name, regs[i].name, idx) == 0)
{
switch (regs[i].size)
{
case 1:
v = *(word8 *)((word8 *)tss_ptr + regs[i].ofs);
break;
case 2:
v = *(word16 *)((word8 *)tss_ptr + regs[i].ofs);
break;
case 4:
v = *(word32 *)((word8 *)tss_ptr + regs[i].ofs);
break;
}
return v + syms_name2val(name+idx);
}
}
for (i=0; i<idx; i++)
if (name[i] == '#')
{
FILENODE f;
LINENODE l;
int lnum;
sscanf(name+i+1, "%d", &lnum);
for (f.me=file_list; f.me; f.me=f.next)
{
symsget(f.me, &f, sizeof(f));
symsget(f.me+sizeof(f), tmps, f.name_len);
if ((strncmp(name, tmps, i) == 0) && (tmps[i] == 0))
{
for (l.me=f.line_list; l.me; l.me=l.next)
{
symsget(l.me, &l, sizeof(l));
if (l.num == lnum)
return l.addr + syms_name2val(name+idx);
}
printf("undefined line number %.*s\n", idx, name);
undefined_symbol = 1;
return 0;
}
}
printf("Undefined file name %.*s\n", i, name);
undefined_symbol = 1;
return 0;
}
s.me = symtree_root;
while (s.me)
{
symsget(s.me, &s, sizeof(s));
symsget(s.me+sizeof(s), tmps, s.name_len);
cval = strncmp(name, tmps, idx);
if ((cval == 0) && tmps[idx])
cval = -1;
if (cval == 0)
return s.val*sign + syms_name2val(name+idx);
else if (cval < 0)
s.me = s.nleft;
else
s.me = s.nright;
}
s.me = symtree_root;
while (s.me)
{
symsget(s.me, &s, sizeof(s));
symsget(s.me+sizeof(s), tmps, s.name_len);
if (tmps[0] == '_')
cval = strncmp(name, tmps+1, idx);
else
cval = '_' - tmps[0];
if ((cval == 0) && tmps[idx+1])
cval = -1;
if (cval == 0)
return s.val*sign + syms_name2val(name+idx);
else if (cval < 0)
s.me = s.nleft;
else
s.me = s.nright;
}
printf("Undefined symbol %.*s\n", idx, name);
undefined_symbol = 1;
return 0;
}
static char noname_buf[11];
char *syms_val2name(word32 val, word32 *delta)
{
SYMTREE s, lasts;
if (delta)
*delta = 0;
lasts.me = 0;
s.me = symtree_root;
while (s.me)
{
symsget(s.me, &s, sizeof(s));
if (s.val <= val)
lasts.me = s.me;
if (val == s.val)
{
while (s.vdown)
symsget(s.vdown, &s, sizeof(s));
symsget(s.me+sizeof(s), tmps2, s.name_len);
return tmps2;
}
else if (val < s.val)
s.me = s.vleft;
else
s.me = s.vright;
}
if (lasts.me)
{
symsget(lasts.me, &lasts, sizeof(lasts));
while (lasts.vdown)
symsget(lasts.vdown, &lasts, sizeof(lasts));
symsget(lasts.me+sizeof(lasts), tmps2, lasts.name_len);
if (strcmp(tmps2, "_etext") == 0)
goto noname;
if (strcmp(tmps2, "_end") == 0)
goto noname;
if (delta)
*delta = val - lasts.val;
return tmps2;
}
noname:
sprintf(noname_buf, "%#lx", val);
return noname_buf;
}
char *syms_val2line(word32 val, int *lineret, int exact)
{
FILENODE filen;
LINENODE linen, closest;
closest.me = 0;
for (filen.me = file_list; filen.me; filen.me=filen.next)
{
symsget(filen.me, &filen, sizeof(filen));
if ((val <= filen.last_addr) && (val >= filen.first_addr))
{
for (linen.me=filen.line_list; linen.me; linen.me = linen.next)
{
symsget(linen.me, &linen, sizeof(linen));
if (val == linen.addr)
{
*lineret = linen.num;
symsget(filen.me+sizeof(filen), tmps2, filen.name_len);
return tmps2;
}
if (val > linen.addr)
{
if (!closest.me)
closest.me = linen.me;
else if (closest.addr < linen.addr)
closest.me = linen.me;
}
}
if (closest.me && !exact)
{
symsget(closest.me, &closest, sizeof(closest));
*lineret = closest.num;
symsget(filen.me+sizeof(filen), tmps2, filen.name_len);
return tmps2;
}
}
}
return 0;
}
static char type2char(type)
{
switch (type)
{
case N_TEXT:
return 't';
case N_TEXT | N_EXT:
return 'T';
case N_DATA:
return 'd';
case N_DATA | N_EXT:
return 'D';
case N_BSS:
return 'b';
case N_BSS | N_EXT:
return 'B';
default:
return ' ';
}
}
static int linecnt, quit_list;
static syms_listwild2(word32 s_pos, char *pattern)
{
SYMTREE s;
char *name;
int lnum;
s.me = s_pos;
if ((s.me == 0) || quit_list)
return;
symsget(s.me, &s, sizeof(s));
syms_listwild2(s.vleft, pattern);
if (quit_list)
return;
symsget(s.me+sizeof(s), tmps, s.name_len);
if (wild(pattern, tmps))
{
if (++linecnt > 20)
{
printf("--- More ---");
switch (getch())
{
case ' ':
linecnt = 0;
break;
case 13:
linecnt--;
break;
case 'q':
quit_list = 1;
return;
}
printf("\r \r");
}
printf("0x%08lx %c %s", s.val, type2char(s.type), tmps);
name = syms_val2line(s.val, &lnum, 0);
if (name)
printf(", line %d of %s", lnum, name);
mputchar('\n');
}
syms_listwild2(s.vdown, pattern);
if (quit_list)
return;
syms_listwild2(s.vright, pattern);
}
void syms_listwild(char *pattern)
{
quit_list = linecnt = 0;
syms_listwild2(symtree_root, pattern);
}
#endif